package cn.aj.basic.service.impl;

import cn.aj.basic.constant.WeChatLoginConstant;
import cn.aj.basic.constant.WxSmsConstant;
import cn.aj.basic.exception.BussinessException;
import cn.aj.basic.jwt.JwtUtils;
import cn.aj.basic.jwt.RsaUtils;
import cn.aj.basic.jwt.UserInfo;
import cn.aj.basic.service.ILoginAccountService;
import cn.aj.basic.tdo.LoginAccountDto;
import cn.aj.basic.tdo.PhoneBinderDto;
import cn.aj.basic.tdo.WeChatCodeDto;
import cn.aj.basic.utils.AjaxResultUtil;
import cn.aj.basic.utils.HttpUtil;
import cn.aj.basic.utils.MD5Utils;
import cn.aj.basic.utils.StrUtils;
import cn.aj.system.domain.Menu;
import cn.aj.system.mapper.MenuMapper;
import cn.aj.system.mapper.PermissionMapper;
import cn.aj.user.domain.Logininfo;
import cn.aj.user.domain.User;
import cn.aj.user.domain.Wxuser;
import cn.aj.user.mapper.LogininfoMapper;
import cn.aj.user.mapper.UserMapper;
import cn.aj.user.mapper.WxuserMapper;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.security.PrivateKey;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

import static cn.aj.basic.jwt.JwtUtils.generateTokenExpireInMinutes;
import static cn.aj.basic.jwt.JwtUtils.generateTokenExpireInSeconds;

@Service
@Slf4j
public class LoginAccountServiceImpl implements ILoginAccountService {

    @Autowired
    private LogininfoMapper logininfoMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private WxuserMapper wxuserMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private PermissionMapper permissionMapper;

    @Autowired
    private MenuMapper menuMapper;

    /**
    * @Title: loadAccount
    * @Description: TODO
    * @Author: Mr.GT
    * @Version: 1.0
    * @Date:  2022/11/26 0026 13:37
    * @Parameters: [loginAccountDto]
    * @Return void
     * 账号登录业务
    */
    @Override
    public Map<String, Object> loadAccount(LoginAccountDto loginAccountDto) {
        // 参数非空校验注解完成
        // 判断登录账号非空,拿loginAccountDto中的参数去查
       Logininfo logininfo = logininfoMapper.loadAccount(loginAccountDto);
       if(null == logininfo) {
           throw new BussinessException("您输入的登录账号或者密码不正确!");
       }

        // 1.密码
        String password = loginAccountDto.getPassword(); // 前端前端传过来的密码明文
        // 2.用MD5生成的盐值和传过来的密码和数据库的进行比较
        // loginAccount数据库查出来的对象
        // 数据库的盐值和密码equals前端的盐值和密码
        String passwordSalt = MD5Utils.encrypByMd5(password + logininfo.getSalt());
        if(logininfo.getPassword().equals(passwordSalt)) {
            throw new BussinessException("输入的登录密码不正确!");
        }

        // toke
        // uuid生成
        return getMap(logininfo);
    }

    /**
    * @Title: getMap
    * @Description: TODO
    * @Author: Mr.GT
    * @Version: 1.0
    * @Date:  2022/11/28 0028 9:06
    * @Parameters: [logininfo]
    * @Return java.util.HashMap<java.lang.String,java.lang.Object>
     *     返回token和logininfo方法抽取
     *     token登录
    */
//    private HashMap<String, Object> getMap(Logininfo logininfo) {
//        String token = UUID.randomUUID().toString();
//        // 保存在在redis中
//        // toke=sessionId loginAccount对象账号和密码=用户信息
//        redisTemplate.opsForValue().set(token, logininfo, 30, TimeUnit.MINUTES);
//        // 做空敏感信息
//        logininfo.setPhone("");
//        // map返回
//        HashMap<String, Object> map = new HashMap<String, Object>();
//        map.put("token", token);
//        map.put("logininfo", logininfo);
//        return map;
//    }

    /**
    * @Title: getMap
    * @Description: TODO
    * @Author: Mr.GT
    * @Version: 1.0
    * @Date:  2022/12/2 0002 21:19
    * @Parameters: [logininfo]
    * @Return java.util.HashMap<java.lang.String,java.lang.Object>
     *     jwt登录
    */
    private HashMap<String, Object> getMap(Logininfo logininfo) {
        // 1 获取JWT
        HashMap<String, Object> map = new HashMap<String, Object>();
        try {
            UserInfo userInfo = new UserInfo();
            userInfo.setLogininfo(logininfo);
            PrivateKey privateKey = RsaUtils.getPrivateKey(JwtUtils.class.getClassLoader().getResource("jwt/pethome_auth_rsa.pri").getFile());
            // 判断
            if(logininfo.getType() == 0) {
                // 菜单
                List<String> permissions = permissionMapper.loadOwnPermissionByLogininId(logininfo.getId());
                // 按钮
                List<Menu> menus = menuMapper.loadOwnPermissionByLogininId(logininfo.getId());
                userInfo.setPermissions(permissions);
                userInfo.setMenus(menus);
                map.put("permissions", permissions);
                map.put("menus", menus);

            }
            String token = generateTokenExpireInMinutes(userInfo, privateKey, 30000);
            // 做空敏感信息
            logininfo.setPhone("");
            // map返回
           // map = new HashMap<String, Object>();
            map.put("token", token);
            map.put("logininfo", logininfo);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }

    /**
    * @Title: loginWechat
    * @Description: TODO
    * @Author: Mr.GT
    * @Version: 1.0
    * @Date:  2022/11/27 0027 21:20
    * @Parameters: [weChatCodeDto]
    * @Return cn.aj.basic.utils.AjaxResultUtil
     * 微信登录
    */
    @Override
    public AjaxResultUtil loginWechat(WeChatCodeDto weChatCodeDto) {
        // 参数校验,注解完成
        // 调用微信第二个接口,根据code获取token
        String wxCode = HttpUtil.httpGet(String.format(WeChatLoginConstant.SECOND_URL,
                WeChatLoginConstant.WECHAT_APPID,
                WeChatLoginConstant.WECHAT_SECRET,
                weChatCodeDto.getWechatCode()));
        // 判断wechatCode非空
        if(StringUtils.isBlank(wxCode)) {
            log.info("调用微信第2个接口失败,wxCode不存在!");
            throw new BussinessException("系统繁忙,请稍后再试!");
        }

        // 前端接受的是一个对象,把wxCode字符串转对象
        JSONObject jsonObject = JSONObject.parseObject(wxCode);
        // 获取token和openid
        String token = jsonObject.getString("access_token"); // TODO
        // 判断token非空 todo
        if(StringUtils.isBlank(token)) {
            log.info("获取token失败!");
            throw new BussinessException("系统繁忙,请稍后再试!");
        }
        String openid = jsonObject.getString("openid"); // TODO
        // 上面走通了,去wxUser表去查询是否存在,根据openid
        Wxuser wxuser = wxuserMapper.getByOpenid(openid);
        // 判断非空
        if(wxuser != null && null != wxuser.getUserId()) {
            Logininfo logininfo = logininfoMapper.getUserId(wxuser.getUserId());
            return AjaxResultUtil.getAjaxResult().success().setResultObj(this.getMap(logininfo)); // todo
        }

        // todo
        StringBuffer stringBuffer = new StringBuffer();
        // "?accessToken="+accessToken+"&openId="+openId;
        stringBuffer.append("?accessToken=").append(token).append("&openId=").append(openid);
        return AjaxResultUtil.getAjaxResult().fail("onBinder").setResultObj(stringBuffer.toString());
    }

    /**
    * @Title: loginBinder
    * @Description: TODO
    * @Author: Mr.GT
    * @Version: 1.0
    * @Date:  2022/11/27 0027 23:43
    * @Parameters: [phoneBinderDto]
    * @Return java.util.Map<java.lang.String,java.lang.Object>
     *     手机强制绑定
    */
    @Override
    public Map<String, Object> loginBinder(PhoneBinderDto phoneBinderDto) {
        // 参数校验,注解完成
        // 短信校验
        // 先获取redis中的短信
        String redisWxMsg = (String) redisTemplate.opsForValue().get(String.format(WxSmsConstant.WX_PHONE_KEY, phoneBinderDto.getPhone()));
        if(StringUtils.isBlank(redisWxMsg) || !redisWxMsg.equals(phoneBinderDto.getVerifyCode())) {
            throw new BussinessException("绑定的手机短信验证不能为空!");
        }
        // 调用第3个接口,获取用户信息
        String str = HttpUtil.httpGet(String.format(WeChatLoginConstant.THIRD_URL, phoneBinderDto.getAccessToken(),phoneBinderDto.getOpenId()));
        if(StringUtils.isBlank(str)) {
            log.info("调用微信第3个接口失败!");
            throw new BussinessException("系统繁忙,请稍后再试!");
        }
        // json转对象
        Wxuser wxuser = JSONObject.parseObject(str, Wxuser.class);
        if(null == wxuser) {
            log.info("调用微信第3个接口失败,没有获取到用户信息!");
            throw new BussinessException("系统繁忙,请稍后再试!");
        }
        // 用户信息校验, 上面走通了,就判断改用是否存在
        // 根据绑定的手机号查询
        Logininfo logininfo = new Logininfo();
        User user = userMapper.loadPhone(phoneBinderDto.getPhone());
        if (user == null) { // 保存用户
            User binderUser = phoneBinderDto.getUser();
            BeanUtils.copyProperties(binderUser, logininfo); // binderUser转logininfo
            logininfo.setType(1);
            logininfo.setDisable(1);
            logininfoMapper.add(logininfo); // 保存登录日志表
            binderUser.setLogininfoId(logininfo.getId());
            userMapper.add(binderUser); // 保存用户表信息
            wxuser.setUserId(binderUser.getId());
            wxuserMapper.add(wxuser); // 保存微信登录用户
        } else { // user!=null
            logininfo = logininfoMapper.getUserId(user.getId());
            wxuser.setUserId(user.getId());
            wxuserMapper.add(wxuser); // 保存微信登录用户
        }
        return getMap(logininfo);
    }

    public static void main(String[] args) {
        String p = "1";
        String s = StrUtils.getComplexRandomString(32);
        String sat = MD5Utils.encrypByMd5(s + p);
        System.out.println(sat);
    }
}
